home *** CD-ROM | disk | FTP | other *** search
/ Aminet 40 / Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso / Aminet / dev / lang / Python16.lha / Python-1.6 / Lib / Python1.6 / distutils / cygwinccompiler.py < prev    next >
Encoding:
Python Source  |  2000-08-13  |  12.9 KB  |  347 lines

  1. """distutils.cygwinccompiler
  2.  
  3. Provides the CygwinCCompiler class, a subclass of UnixCCompiler that
  4. handles the Cygwin port of the GNU C compiler to Windows.  It also contains
  5. the Mingw32CCompiler class which handles the mingw32 port of GCC (same as
  6. cygwin in no-cygwin mode).
  7. """
  8.  
  9. # problems:
  10. #
  11. # * if you use a msvc compiled python version (1.5.2)
  12. #   1. you have to insert a __GNUC__ section in its config.h
  13. #   2. you have to generate a import library for its dll
  14. #      - create a def-file for python??.dll
  15. #      - create a import library using
  16. #             dlltool --dllname python15.dll --def python15.def \
  17. #                       --output-lib libpython15.a
  18. #
  19. #   see also http://starship.python.net/crew/kernr/mingw32/Notes.html
  20. #
  21. # * We use put export_symbols in a def-file, and don't use 
  22. #   --export-all-symbols because it doesn't worked reliable in some
  23. #   tested configurations. And because other windows compilers also
  24. #   need their symbols specified this no serious problem.
  25. #
  26. # tested configurations:
  27. #   
  28. # * cygwin gcc 2.91.57/ld 2.9.4/dllwrap 0.2.4 works 
  29. #   (after patching python's config.h and for C++ some other include files)
  30. #   see also http://starship.python.net/crew/kernr/mingw32/Notes.html
  31. # * mingw32 gcc 2.95.2/ld 2.9.4/dllwrap 0.2.4 works 
  32. #   (ld doesn't support -shared, so we use dllwrap)   
  33. # * cygwin gcc 2.95.2/ld 2.10.90/dllwrap 2.10.90 works now
  34. #   - its dllwrap doesn't work, there is a bug in binutils 2.10.90
  35. #     see also .....
  36. #   - using gcc -mdll instead dllwrap doesn't work without -static because 
  37. #     it tries to link against dlls instead their import libraries. (If
  38. #     it finds the dll first.)
  39. #     By specifying -static we force ld to link against the import libraries, 
  40. #     this is windows standard and there are normally not the necessary symbols 
  41. #     in the dlls.
  42.  
  43. # created 2000/05/05, Rene Liebscher
  44.  
  45. __revision__ = "$Id: cygwinccompiler.py,v 1.6 2000/08/13 01:18:55 gward Exp $"
  46.  
  47. import os,sys,copy
  48. from distutils.unixccompiler import UnixCCompiler
  49. from distutils.file_util import write_file
  50.  
  51. class CygwinCCompiler (UnixCCompiler):
  52.  
  53.     compiler_type = 'cygwin'
  54.     obj_extension = ".o"
  55.     static_lib_extension = ".a"
  56.     shared_lib_extension = ".dll"
  57.     static_lib_format = "lib%s%s"
  58.     shared_lib_format = "%s%s"
  59.     exe_extension = ".exe"
  60.    
  61.     def __init__ (self,
  62.                   verbose=0,
  63.                   dry_run=0,
  64.                   force=0):
  65.  
  66.         UnixCCompiler.__init__ (self, verbose, dry_run, force)
  67.  
  68.         (status, details) = check_config_h()
  69.         self.debug_print("Python's GCC status: %s (details: %s)" %
  70.                          (status, details))
  71.         if status is not CONFIG_H_OK:
  72.             self.warn(
  73.                 "Python's config.h doesn't seem to support your compiler.  " +
  74.                 ("Reason: %s." % details) +
  75.                 "Compiling may fail because of undefined preprocessor macros.")
  76.         
  77.         (self.gcc_version, self.ld_version, self.dllwrap_version) = \
  78.             get_versions()
  79.         self.debug_print(self.compiler_type + ": gcc %s, ld %s, dllwrap %s\n" %
  80.                          (self.gcc_version, 
  81.                           self.ld_version, 
  82.                           self.dllwrap_version) )
  83.  
  84.         # ld_version >= "2.10.90" should also be able to use 
  85.         # gcc -mdll instead of dllwrap
  86.         # Older dllwraps had own version numbers, newer ones use the 
  87.         # same as the rest of binutils ( also ld )
  88.         # dllwrap 2.10.90 is buggy
  89.         if self.ld_version >= "2.10.90": 
  90.             self.linker = "gcc"
  91.         else:
  92.             self.linker = "dllwrap"
  93.  
  94.         # Hard-code GCC because that's what this is all about.
  95.         # XXX optimization, warnings etc. should be customizable.
  96.         self.set_executables(compiler='gcc -mcygwin -O -Wall',
  97.                              compiler_so='gcc -mcygwin -mdll -O -Wall',
  98.                              linker_exe='gcc -mcygwin',
  99.                              linker_so=('%s -mcygwin -mdll -static' %
  100.                                         self.linker))
  101.  
  102.         # cygwin and mingw32 need different sets of libraries 
  103.         if self.gcc_version == "2.91.57":
  104.             # cygwin shouldn't need msvcrt, but without the dlls will crash
  105.             # (gcc version 2.91.57) -- perhaps something about initialization
  106.             self.dll_libraries=["msvcrt"]
  107.             self.warn( 
  108.                 "Consider upgrading to a newer version of gcc")
  109.         else:
  110.             self.dll_libraries=[]
  111.         
  112.     # __init__ ()
  113.  
  114.     def link_shared_object (self,
  115.                             objects,
  116.                             output_filename,
  117.                             output_dir=None,
  118.                             libraries=None,
  119.                             library_dirs=None,
  120.                             runtime_library_dirs=None,
  121.                             export_symbols=None,
  122.                             debug=0,
  123.                             extra_preargs=None,
  124.                             extra_postargs=None,
  125.                             build_temp=None):
  126.         
  127.         # use separate copies, so we can modify the lists
  128.         extra_preargs = copy.copy(extra_preargs or [])
  129.         libraries = copy.copy(libraries or [])
  130.         
  131.         # Additional libraries
  132.         libraries.extend(self.dll_libraries)
  133.         
  134.         # we want to put some files in the same directory as the 
  135.         # object files are, build_temp doesn't help much
  136.  
  137.         # where are the object files
  138.         temp_dir = os.path.dirname(objects[0])
  139.  
  140.         # name of dll to give the helper files (def, lib, exp) the same name
  141.         (dll_name, dll_extension) = os.path.splitext(
  142.             os.path.basename(output_filename))
  143.  
  144.         # generate the filenames for these files
  145.         def_file = None # this will be done later, if necessary
  146.         exp_file = os.path.join(temp_dir, dll_name + ".exp")
  147.         lib_file = os.path.join(temp_dir, 'lib' + dll_name + ".a")
  148.  
  149.         #extra_preargs.append("--verbose")
  150.         if self.linker == "dllwrap":
  151.             extra_preargs.extend([#"--output-exp",exp_file,
  152.                                   "--output-lib",lib_file,
  153.                                  ])
  154.         else:
  155.             # doesn't work: bfd_close build\...\libfoo.a: Invalid operation
  156.             extra_preargs.extend([#"-Wl,--out-implib,%s" % lib_file,
  157.                                  ])
  158.        
  159.         #  check what we got in export_symbols
  160.         if export_symbols is not None:
  161.             # Make .def file
  162.             # (It would probably better to check if we really need this, 
  163.             # but for this we had to insert some unchanged parts of 
  164.             # UnixCCompiler, and this is not what we want.) 
  165.             def_file = os.path.join(temp_dir, dll_name + ".def")
  166.             contents = [
  167.                 "LIBRARY %s" % os.path.basename(output_filename),
  168.                 "EXPORTS"]
  169.             for sym in export_symbols:
  170.                 contents.append(sym)
  171.             self.execute(write_file, (def_file, contents),
  172.                          "writing %s" % def_file)
  173.  
  174.         if def_file:
  175.             if self.linker == "dllwrap":
  176.                 # for dllwrap we have to use a special option
  177.                 extra_preargs.append("--def")
  178.             # for gcc/ld it is specified as any other object file    
  179.             extra_preargs.append(def_file)
  180.                                                  
  181.         # who wants symbols and a many times larger output file
  182.         # should explicitly switch the debug mode on 
  183.         # otherwise we let dllwrap/ld strip the output file
  184.         # (On my machine unstripped_file = stripped_file + 254KB
  185.         #   10KB < stripped_file < ??100KB ) 
  186.         if not debug: 
  187.             extra_preargs.append("-s") 
  188.         
  189.         UnixCCompiler.link_shared_object(self,
  190.                             objects,
  191.                             output_filename,
  192.                             output_dir,
  193.                             libraries,
  194.                             library_dirs,
  195.                             runtime_library_dirs,
  196.                             None, # export_symbols, we do this in our def-file
  197.                             debug,
  198.                             extra_preargs,
  199.                             extra_postargs,
  200.                             build_temp)
  201.         
  202.     # link_shared_object ()
  203.  
  204. # class CygwinCCompiler
  205.  
  206.  
  207. # the same as cygwin plus some additional parameters
  208. class Mingw32CCompiler (CygwinCCompiler):
  209.  
  210.     compiler_type = 'mingw32'
  211.  
  212.     def __init__ (self,
  213.                   verbose=0,
  214.                   dry_run=0,
  215.                   force=0):
  216.  
  217.         CygwinCCompiler.__init__ (self, verbose, dry_run, force)
  218.         
  219.         # A real mingw32 doesn't need to specify a different entry point,
  220.         # but cygwin 2.91.57 in no-cygwin-mode needs it.
  221.         if self.gcc_version <= "2.91.57":
  222.             entry_point = '--entry _DllMain@12'
  223.         else:
  224.             entry_point = ''
  225.  
  226.         self.set_executables(compiler='gcc -mno-cygwin -O -Wall',
  227.                              compiler_so='gcc -mno-cygwin -mdll -O -Wall',
  228.                              linker_exe='gcc -mno-cygwin',
  229.                              linker_so='%s -mno-cygwin -mdll -static %s' 
  230.                                         % (self.linker, entry_point))
  231.         # Maybe we should also append -mthreads, but then the finished
  232.         # dlls need another dll (mingwm10.dll see Mingw32 docs)
  233.         # (-mthreads: Support thread-safe exception handling on `Mingw32')       
  234.         
  235.         # no additional libraries needed 
  236.         self.dll_libraries=[]
  237.         
  238.     # __init__ ()
  239.  
  240. # class Mingw32CCompiler
  241.  
  242. # Because these compilers aren't configured in Python's config.h file by
  243. # default, we should at least warn the user if he is using a unmodified
  244. # version.
  245.  
  246. CONFIG_H_OK = "ok"
  247. CONFIG_H_NOTOK = "not ok"
  248. CONFIG_H_UNCERTAIN = "uncertain"
  249.  
  250. def check_config_h():
  251.  
  252.     """Check if the current Python installation (specifically, config.h)
  253.     appears amenable to building extensions with GCC.  Returns a tuple
  254.     (status, details), where 'status' is one of the following constants:
  255.       CONFIG_H_OK
  256.         all is well, go ahead and compile
  257.       CONFIG_H_NOTOK
  258.         doesn't look good
  259.       CONFIG_H_UNCERTAIN
  260.         not sure -- unable to read config.h
  261.     'details' is a human-readable string explaining the situation.
  262.  
  263.     Note there are two ways to conclude "OK": either 'sys.version' contains
  264.     the string "GCC" (implying that this Python was built with GCC), or the
  265.     installed "config.h" contains the string "__GNUC__".
  266.     """
  267.  
  268.     # XXX since this function also checks sys.version, it's not strictly a
  269.     # "config.h" check -- should probably be renamed...
  270.  
  271.     from distutils import sysconfig
  272.     import string,sys
  273.     # if sys.version contains GCC then python was compiled with
  274.     # GCC, and the config.h file should be OK
  275.     if string.find(sys.version,"GCC") >= 0:
  276.         return (CONFIG_H_OK, "sys.version mentions 'GCC'")
  277.     
  278.     fn = sysconfig.get_config_h_filename()
  279.     try:
  280.         # It would probably better to read single lines to search.
  281.         # But we do this only once, and it is fast enough 
  282.         f = open(fn)
  283.         s = f.read()
  284.         f.close()
  285.         
  286.     except IOError, exc:
  287.         # if we can't read this file, we cannot say it is wrong
  288.         # the compiler will complain later about this file as missing
  289.         return (CONFIG_H_UNCERTAIN,
  290.                 "couldn't read '%s': %s" % (fn, exc.strerror))
  291.  
  292.     else:
  293.         # "config.h" contains an "#ifdef __GNUC__" or something similar
  294.         if string.find(s,"__GNUC__") >= 0:
  295.             return (CONFIG_H_OK, "'%s' mentions '__GNUC__'" % fn)
  296.         else:
  297.             return (CONFIG_H_NOTOK, "'%s' does not mention '__GNUC__'" % fn)
  298.  
  299.  
  300.  
  301. def get_versions():
  302.     """ Try to find out the versions of gcc, ld and dllwrap.
  303.         If not possible it returns None for it.
  304.     """
  305.     from distutils.version import StrictVersion
  306.     from distutils.spawn import find_executable
  307.     import re
  308.         
  309.     gcc_exe = find_executable('gcc')
  310.     if gcc_exe:
  311.         out = os.popen(gcc_exe + ' -dumpversion','r')
  312.         out_string = out.read()
  313.         out.close()
  314.         result = re.search('(\d+\.\d+\.\d+)',out_string)
  315.         if result:
  316.             gcc_version = StrictVersion(result.group(1))
  317.         else:
  318.             gcc_version = None
  319.     else:
  320.         gcc_version = None
  321.     ld_exe = find_executable('ld')
  322.     if ld_exe:
  323.         out = os.popen(ld_exe + ' -v','r')
  324.         out_string = out.read()
  325.         out.close()
  326.         result = re.search('(\d+\.\d+\.\d+)',out_string)
  327.         if result:
  328.             ld_version = StrictVersion(result.group(1))
  329.         else:
  330.             ld_version = None
  331.     else:
  332.         ld_version = None
  333.     dllwrap_exe = find_executable('dllwrap')
  334.     if dllwrap_exe:
  335.         out = os.popen(dllwrap_exe + ' --version','r')
  336.         out_string = out.read()
  337.         out.close()
  338.         result = re.search(' (\d+\.\d+\.\d+)',out_string)
  339.         if result:
  340.             dllwrap_version = StrictVersion(result.group(1))
  341.         else:
  342.             dllwrap_version = None
  343.     else:
  344.         dllwrap_version = None
  345.     return (gcc_version, ld_version, dllwrap_version)
  346.  
  347.